//===============================================================================
// Microsoft patterns & practices
// Mobile Client Software Factory - July 2006
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.Mobile.DataAccess;
using System.Data.SqlServerCe;
using System.Threading;
using Microsoft.Practices.TestUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.Practices.Mobile.Subscriptions.Tests
{
	[TestClass]
	public class SubscriptionManagerTwoDbFixture
	{
		private string connectionStringPattern = @"Data Source=""{0}""";
		private string connectionString;
		private string subConnectionString;

		private TestResourceFile dbFile;
		private TestResourceFile dbInfoFile;
		private Database refDbService;		// Subscription/reference data database
		private Database subDbService;		// Subscription manager database

		[TestInitialize]
		public void CopyDatabaseFile()
		{
			dbFile = new TestResourceFile(this, "TestSubscription.sdf");
			connectionString = String.Format(connectionStringPattern, dbFile.Filename);

			dbInfoFile = new TestResourceFile(this, "TestSubscriptionInfo.sdf");
			subConnectionString = String.Format(connectionStringPattern, dbInfoFile.Filename);

			refDbService = new SqlDatabase(connectionString);
			subDbService = new SqlDatabase(subConnectionString);
		}

		[TestCleanup]
		public void RemoveDatabaseFile()
		{
			refDbService.Dispose();
			subDbService.Dispose();
			
			dbFile.Dispose();
			dbInfoFile.Dispose();
		}

		[TestMethod]
		public void CanCreateSubscriptionManagerUsingTwoDatabases()
		{
			SqlSubscriptionManager sub = CreateSubscriptionManager();
			Assert.IsNotNull(sub);
		}

		[TestMethod]
		public void SubscriptionInfoPutInCorrectDatabase()
		{
			SqlSubscriptionManager sub = CreateSubscriptionManager();

			Assert.IsTrue(subDbService.TableExists("SubscriptionInfo"), "SubscriptionInfo not found in Subscription Manager database");
			Assert.IsFalse(refDbService.TableExists("SubscriptionInfo"), "SubscriptionInfo found, but not expected, in reference database");
		}

		[TestMethod]
		public void NewSubscriptionCanReturnData()
		{
			SqlSubscriptionManager subMgr = CreateSubscriptionManager();

			SubscriptionParameters subParams = CreateSubscriptionParams("PubCustomers", "CustomersTest");

			subMgr.Add(subParams);

			Assert.IsFalse(refDbService.TableExists("Customer"));

			subMgr.Synchronize(subMgr.Subscriptions[0]);

			Assert.IsTrue(refDbService.TableExists("Customer"));
			Assert.IsFalse(subDbService.TableExists("Customer"));
			Assert.IsTrue(CountCustomers(connectionString) > 0, "Didn't return any records");
		}

		[TestMethod]
		public void LastSyncTimeBecomesNonNullAfterSync()
		{
			SubscriptionParameters subParams = CreateSubscriptionParams("PubCustomers", "CustomersTest");
			SqlSubscriptionManager subMgr = CreateSubscriptionManager();
			subMgr.Add(subParams);
			
			Subscription sub = subMgr.Subscriptions[0];
			Assert.IsNull(sub.LastSyncTime);
			subMgr.Synchronize(sub);

			subMgr = CreateSubscriptionManager();
			Assert.IsNotNull(sub.LastSyncTime);
		}

		[TestMethod]
		public void LastSyncTimeUpdatedAfterSync()
		{
			SqlSubscriptionManager subMgr = CreateSubscriptionManager();
			SubscriptionParameters subParams = CreateSubscriptionParams("PubCustomers", "CustomersTest");
			subMgr.Add(subParams);
			Assert.IsNull(subMgr.Subscriptions[0].LastSyncTime);

			subMgr.Synchronize(subMgr.Subscriptions[0]);
			Assert.IsNotNull(subMgr.Subscriptions[0].LastSyncTime);
			DateTime oldSyncTime = (DateTime)subMgr.Subscriptions[0].LastSyncTime;
			Thread.Sleep(1000);
			subMgr.Synchronize(subMgr.Subscriptions[0]);
			Assert.IsTrue(subMgr.Subscriptions[0].LastSyncTime > oldSyncTime);
		}

		[TestMethod]
		public void CanDropSubscription()
		{
			SubscriptionParameters subParams = CreateSubscriptionParams("PubCustomers", "CustomersTest");
			SqlSubscriptionManager subMgr = CreateSubscriptionManager();
			subMgr.Add(subParams);
			subMgr.Synchronize(subMgr.Subscriptions[0]);

			subMgr = CreateSubscriptionManager();
			subMgr.Drop(subMgr.Subscriptions[0]);
			Assert.AreEqual(0, subMgr.Subscriptions.Count);

			subMgr = CreateSubscriptionManager();
			Assert.AreEqual(0, subMgr.Subscriptions.Count);
		}

		[TestMethod]
		public void AsynchronousSyncUpdatesLastSyncTime()
		{
			SubscriptionParameters subParams = CreateSubscriptionParams("PubCustomers", "CustomersTest");
			SqlSubscriptionManager subMgr = CreateSubscriptionManager();
			subMgr.Add(subParams);

			Subscription sub = subMgr.Subscriptions[0];

			subMgr.BeginSynchronize(sub);
			sub.AsyncResult.AsyncWaitHandle.WaitOne(50000, false);
			Assert.IsTrue(sub.AsyncResult.IsCompleted);
			Assert.IsNotNull(sub.LastSyncTime);

			subMgr.EndSynchronize(sub);

			Assert.IsNotNull(sub.LastSyncTime);
		}

		[TestMethod]
		public void AsynchronousSyncUpdatesCorrectDatabase()
		{
			SubscriptionParameters subParams = CreateSubscriptionParams("PubCustomers", "CustomersTest");
			SqlSubscriptionManager subMgr = CreateSubscriptionManager();
			subMgr.Add(subParams);

			Subscription sub = subMgr.Subscriptions[0];

			subMgr.BeginSynchronize(sub);
			sub.AsyncResult.AsyncWaitHandle.WaitOne(50000, false);
			Assert.IsTrue(sub.AsyncResult.IsCompleted);

			subMgr.EndSynchronize(sub);

			Assert.IsTrue(refDbService.TableExists("Customer"));
			Assert.IsFalse(subDbService.TableExists("Customer"));
			Assert.IsTrue(CountCustomers(connectionString) > 0, "Didn't return any records");
		}

		private SqlSubscriptionManager CreateSubscriptionManager()
		{
			this.subConnectionString = String.Format(connectionStringPattern, dbFile.Filename);
			SqlSubscriptionManager sub = new SqlSubscriptionManager(refDbService, subDbService, new SubscriptionCredentialServiceMock());

			return sub;
		}

		private static SubscriptionParameters CreateSubscriptionParams(string publication, string subscriber)
		{
			SubscriptionParameters subscription = new SubscriptionParameters();
			subscription.Publication = publication;
			subscription.Publisher = SubscriptionManagerFixture.publisherServer;
			subscription.PublisherDatabase = "AdventureWorksMobileStaging";
			subscription.InternetUrl = SubscriptionManagerFixture.GetUrl();
			subscription.Subscriber = subscriber;
			subscription.Filter = "DE";
			return subscription;
		}

		private int CountCustomers(string connectString)
		{
			using (SqlCeConnection connection = new SqlCeConnection(connectString))
			{
				connection.Open();

				string sql = @"
						SELECT	COUNT(*)
						FROM	Customer";

				using (SqlCeCommand command = new SqlCeCommand(sql, connection))
				{
					return (int)command.ExecuteScalar();
				}
			}
		}

	}
}
